﻿//
// Copyright (c) 2024 BPer
//

#include <bperutil/buffer2/BPerMediaBuffer2.h>
#include <bperutil/BPerAvInfoType.h>

void bPer_mediaBuffer2_resetIndex(BPerMediaBufferSession2 *session) {
	bPer_thread_mutex_lock(&session->mlock);
	session->putIndex = 0;
	session->getIndex = 0;
	session->nextIndex = 0;

	session->ret = 0;
	session->size = 0;
	bPer_thread_mutex_unlock(&session->mlock);
}

void bPer_mediaBuffer2_initFrames(BPerMediaBufferSession2 *session,
		int32_t pnum, int unitsize) {
	if (session->bufferManager == NULL)
		session->bufferManager = (uint8_t*) bPer_calloc(unitsize, pnum);
	if (session->frames == NULL) {
		session->frames = (BPerFrame**) bPer_calloc(sizeof(BPerFrame*), pnum);
		for (int32_t i = 0; i < pnum; i++) {
			session->frames[i] = (BPerFrame*) bPer_calloc(sizeof(BPerFrame), 1);
			bPer_memset(session->frames[i], 0, sizeof(BPerFrame));
			session->frames[i]->payload = session->bufferManager + i * unitsize;
		}
	}
}

void bPer_mediaBuffer2_putFrame(BPerMediaBufferSession2 *session,
		BPerFrame *pframe) {
	if (session == NULL || pframe == NULL)
		return;
	bPer_thread_mutex_lock(&session->mlock);
	if (session->size >= session->cache_num)
		goto cleanup;
	bPer_frame_copy_buffer(pframe, session->frames[session->putIndex++]);
	if (session->putIndex >= session->cache_num)
		session->putIndex = 0;
	session->size++;
	cleanup:
	bPer_thread_mutex_unlock(&session->mlock);
	return;

}

void bPer_mediaBuffer2_getFrame(BPerMediaBufferSession2 *session,
		BPerFrame *pframe) {
	if (session == NULL || pframe == NULL)
		return;
	bPer_thread_mutex_lock(&session->mlock);
	if (session->size == 0)
		goto cleanup;
	bPer_frame_copy_buffer(session->frames[session->getIndex++], pframe);
	if (session->getIndex >= session->cache_num)
		session->getIndex = 0;
	session->size--;
	cleanup:
	bPer_thread_mutex_unlock(&session->mlock);
	return;
}

uint8_t* bPer_mediaBuffer2_getFrameRef(BPerMediaBufferSession2 *session,
		BPerFrame *pframe) {
	uint8_t *p=NULL;
	if (session == NULL || pframe == NULL)
		return p;
	bPer_thread_mutex_lock(&session->mlock);
	if (session->size == 0)
		goto cleanup;
	bPer_frame_copy_nobuffer(session->frames[session->getIndex], pframe);
	p = session->frames[session->getIndex]->payload;
	session->getIndex++;
	if (session->getIndex >= session->cache_num)
		session->getIndex = 0;
	session->size--;
	cleanup:
	bPer_thread_mutex_unlock(&session->mlock);
	return p;
}

BPerFrame* bPer_mediaBuffer2_getCurFrameRef(BPerMediaBufferSession2 *session) {
	if (session == NULL || session->size == 0)
		return NULL;
	session->nextIndex = session->getIndex;
	if (session->nextIndex >= session->cache_num)
		session->nextIndex = 0;
	return session->frames[session->nextIndex];
}

int64_t bPer_mediaBuffer2_getNextFrameTimestamp(
		BPerMediaBufferSession2 *session) {
	if (!session->size)
		return 0;
	session->nextIndex = session->getIndex;
	if (session->nextIndex >= session->cache_num)
		session->nextIndex = 0;
	return session->frames[session->nextIndex]->pts;

}

void bPer_create_mediaBuffer2(BPerMediaBuffer2 *buf) {
	BPerMediaBufferSession2 *session = &buf->session;
	bPer_thread_mutex_init(&session->mlock, NULL);
	bPer_mediaBuffer2_resetIndex(session);
	session->cache_num = 5;
	session->mediaType = 1;
	session->uid = -1;
	session->frames = NULL;
	session->bufferManager = NULL;

	buf->initFrames = bPer_mediaBuffer2_initFrames;
	buf->getCurFrameRef = bPer_mediaBuffer2_getCurFrameRef;
	buf->getFrameRef = bPer_mediaBuffer2_getFrameRef;
	buf->getNextFrameTimestamp = bPer_mediaBuffer2_getNextFrameTimestamp;
	buf->putFrame = bPer_mediaBuffer2_putFrame;
	buf->getFrame = bPer_mediaBuffer2_getFrame;
	buf->resetIndex = bPer_mediaBuffer2_resetIndex;
}

void bPer_destroy_mediaBuffer2(BPerMediaBuffer2 *buf) {
	BPerMediaBufferSession2 *session = &buf->session;
	if (session->frames) {
		for (uint32_t i = 0; i < session->cache_num; i++) {
			bPer_free(session->frames[i]);
		}
		bPer_free(session->frames);
	}
	bPer_free(session->bufferManager);
	bPer_thread_mutex_destroy(&session->mlock);
}
